/**
 * 
 */
package org.apache.james.hibernate;

import java.util.List;

import org.apache.james.api.imap.ImapConstants;
import org.apache.james.hibernate.entity.DbMailbox;
import org.apache.james.hibernate.entity.ImapUserInfo;
import org.apache.james.hibernate.entity.NamespaceImpl;
import org.apache.james.mailboxmanager.GeneralMessageSet;
import org.apache.james.mailboxmanager.ListResult;
import org.apache.james.mailboxmanager.MailboxManagerException;
import org.apache.james.mailboxmanager.impl.ListResultImpl;
import org.apache.james.mailboxmanager.mailbox.GeneralMailbox;
import org.apache.james.mailboxmanager.mailbox.GeneralMailboxSession;
import org.apache.james.mailboxmanager.mailbox.ImapMailboxSession;
import org.apache.james.mailboxmanager.mailbox.MailboxSession;
import org.apache.james.mailboxmanager.manager.MailboxManager;
import org.apache.james.mailboxmanager.tracking.MailboxCache;
import org.apache.james.mailboxmanager.tracking.UidChangeTracker;
import org.apache.james.mailboxmanager.wrapper.ImapMailboxSessionWrapper;
import org.apache.james.services.User;
import org.apache.log4j.Logger;

/**
 * @author zsombor
 *
 */
public class HibernateMailboxManager implements MailboxManager {

	final static Logger LOG = Logger.getLogger(HibernateMailboxManager.class);

	MailboxPersistenceManager mailboxManager;

	
	User user;
	private ImapUserInfo userInfo;
	
	MailboxCache cache;
	
	HibernateMailboxManagerProvider provider;
	
	
	public HibernateMailboxManager(HibernateMailboxManagerProvider provider,MailboxPersistenceManager mailboxManager,
			User user, MailboxCache cache) {
		this.provider = provider;
		this.mailboxManager = mailboxManager;
		this.user = user;
		this.cache = cache;
	}

	@Override
	public void close() {
		provider.removeMailboxManager(user);
	}

	@Override
	public void copyMessages(GeneralMailbox from, GeneralMessageSet set,
			String to) throws MailboxManagerException {
		// TODO Auto-generated method stub
		
	}

	@Override
	public boolean createInbox(User user) throws MailboxManagerException {
		LOG.info("createInbox (user):"+user.getUserName()+", userinfo: "+getUserInfo().getName());
		if (!user.getUserName().equals(userInfo.getName())) {
			throw new MailboxManagerException("createInbox (user):"+user.getUserName()+", userinfo: "+userInfo.getName());
		}
		return mailboxManager.createInbox(getUserInfo());
	}

	@Override
	public void createMailbox(String mailboxName)
			throws MailboxManagerException {

		ImapUserInfo imapUserInfo = getUserInfo();
		NamespaceImpl ns = imapUserInfo.getDefaultNamespace();
		// TODO : parse the correct namespace 
		if (mailboxName.startsWith(ImapConstants.NAMESPACE_PREFIX)) {
			int idx = mailboxName.indexOf('.');
			if (idx!=-1) {
				String nsName = mailboxName.substring(1,idx);
				ns = imapUserInfo.getNamespace(nsName);
			}
			mailboxName = mailboxName.substring(1);
		}
		mailboxManager.createMailbox(imapUserInfo, ns, mailboxName);
	}

	@Override
	public void deleteMailbox(String mailboxName)
			throws MailboxManagerException {
		
		mailboxManager.deleteMailbox(getUserInfo(),mailboxName);
		
	}

	@Override
	public boolean existsMailbox(String mailboxName)
			throws MailboxManagerException {
		return mailboxManager.existsMailbox(getUserInfo(),mailboxName);
	}

	@Override
	public GeneralMailboxSession getGeneralMailboxSession(String mailboxName)
			throws MailboxManagerException {
        return getImapMailboxSession(mailboxName);
	}

	@Override
	public ImapMailboxSession getImapMailboxSession(String mailboxName)
			throws MailboxManagerException {
		synchronized (cache) {
//			MailboxRow mailboxRow = MailboxRowPeer.retrieveByName(mailboxName);
			mailboxName = filterNamespaceChar(mailboxName);
			DbMailbox mailboxRow = mailboxManager.getMailbox(mailboxName);

			if (mailboxRow != null) {
				UidChangeTracker tracker = (UidChangeTracker) cache
						.getMailboxTracker(mailboxName, UidChangeTracker.class);
				if (tracker == null) {
					tracker = new UidChangeTracker(cache, mailboxName,
							mailboxRow.getUid());
					cache.add(mailboxName, tracker);
				}
				LOG.info("getImapMailboxSession (mailboxName):" + mailboxName);
				return new ImapMailboxSessionWrapper(new ImapMailboxImpl(
						mailboxManager, mailboxRow, tracker, getUserInfo()));
				//new ImapMailboxSessionWrapper(new ImapMailboxImpl(
						//mailboxRow, tracker));
			} else {
				cache.notFound(mailboxName);
				throw new MailboxManagerException("Mailbox '" + mailboxName
						+ "' not found.");
			}
		}
	}

	private String filterNamespaceChar(String mailboxName) {
		if ((mailboxName.length()>0) && mailboxName.charAt(0)==ImapConstants.NAMESPACE_PREFIX_CHAR) {
			mailboxName = mailboxName.substring(1);
		}
		return mailboxName;
	}

	@Override
	public MailboxSession getMailboxSession(String mailboxName,
			boolean autoCreate) throws MailboxManagerException {
        if (autoCreate && !existsMailbox(mailboxName)) {
            
        	createMailbox(mailboxName);
        }
        return getImapMailboxSession(mailboxName);
	}

	@Override
	public ListResult[] list(String base, String expression, boolean subscribed)
			throws MailboxManagerException {
		LOG.info("list (base, expression, subscribed):'"+base+"','"+expression+"',"+subscribed);
		base = filterNamespaceChar(base);
		
		List<String> result = mailboxManager.listMailboxNames(getUserInfo(), base,expression, subscribed);
		ListResult[] listResult = new ListResult[result.size()];
		for (int i=0;i<listResult.length;i++) {
			//ImapConstants.NAMESPACE_PREFIX_CHAR
			String name = result.get(i);
			listResult[i] = new ListResultImpl(
					new StringBuilder(name.length()+1).append(ImapConstants.NAMESPACE_PREFIX_CHAR).append(name).toString(), 
					".");
		}
		return listResult;
	}

	@Override
	public void renameMailbox(String from, String to)
			throws MailboxManagerException {
		from = filterNamespaceChar(from);
		to = filterNamespaceChar(to);

		LOG.info("renameMailbox (from, to):'" + from + "','" + to + '\'');
		mailboxManager.renameMailbox(getUserInfo(), from, to);
	}

	@Override
	public void setSubscription(String mailboxName, boolean value)
			throws MailboxManagerException {

		LOG.info("setSubscription (mailboxName, value):'" + mailboxName + "',"
				+ value);
	}

	protected ImapUserInfo getUserInfo() {
		if (userInfo==null) {
			userInfo = provider.getImapUserInfo(user);
		}
		return userInfo;
	}

}
